package elijah.base.utils;

import android.content.Context;
import android.content.ContextWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.viewbinding.ViewBinding;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import elijah.base.thread.Scheduled;

public class ClassUtils {

    public static <T> Map<String, T> objectToMap(Class<T> t, Object object) {
        Map<String, T> dataMap = new HashMap<>();
        Class<?> clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            try {
                field.setAccessible(true);
                Object o = field.get(object);
                if (o != null && t.equals(o.getClass())) {
                    dataMap.put(field.getName(), (T) o);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return dataMap;
    }

    public static Map<String, Object> objectToMap(Object object) {
        Map<String, Object> dataMap = new HashMap<>();
        Class<?> clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            try {
                field.setAccessible(true);
                dataMap.put(field.getName(), field.get(object));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return dataMap;
    }

    public static Map<String, String> getFields(String key, Object obj) {
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < declaredFields.length; i++) {
            Field field = declaredFields[i];
            field.setAccessible(true);
            try {
                Object o = field.get(obj);
                if (o != null) {
                    map.put(key + "-" + field.getName(), o.toString());
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }


    public  static  Class<?> getParamClass(Class<?> clz, int index) {
        Type[] actualTypeArguments = ((ParameterizedType) clz.getGenericSuperclass()).getActualTypeArguments();
        return (Class<?>) actualTypeArguments[index];
    }

    public static <V extends ViewBinding> Object getViewBinding(Class<?> clz, int index, ViewGroup viewGroup) {
        return getViewBinding(clz, index, viewGroup, false);
    }

    public static <V extends ViewBinding> Object getViewBinding(Class<?> clz, int index, ViewGroup viewGroup, boolean attach) {
        Class<?> aClass = ClassUtils.getParamClass(clz, index);
        try {
            Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
            return (V) method.invoke(null, LayoutInflater.from(viewGroup.getContext()), viewGroup, attach);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new IllegalArgumentException(e);

        }
    }

    public static <V extends ViewBinding> Object getViewBinding(Class<?> clz, int index, Context context) {
        Class<?> aClass = ClassUtils.getParamClass(clz, index);
        try {
            Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
            return (V) method.invoke(null, LayoutInflater.from(context), null, false);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new IllegalArgumentException(e);

        }
    }

    public static <V extends ViewBinding> Object getViewBinding(Class<?> clz, LayoutInflater inflater, int index) {
        Class<?> aClass = ClassUtils.getParamClass(clz, index);
        try {
            Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
            return (V) method.invoke(null, inflater, null, false);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new IllegalArgumentException(e);
        }
    }

    public static List<Method> getAnnotation(Class<?> clz, Class<? extends Annotation> annotationClass) {
        List<Method> methods = new ArrayList<>();

        for (Method method : clz.getMethods()) {
            method.setAccessible(true);
            if (method.isAnnotationPresent(annotationClass)) {
                methods.add(method);
            }
        }
        for (Method method : clz.getDeclaredMethods()) {
            method.setAccessible(true);
            if (!methods.contains(method)&&method.isAnnotationPresent(annotationClass)) {
                methods.add(method);
            }

        }
        Class<?> cls;
        while ((cls = clz.getSuperclass()) != null) {
            if (cls != ContextWrapper.class) {
                break;
            }
            if (cls != View.class) {
                break;
            }
            if (cls != ViewGroup.class) {
                break;
            }
            methods.addAll(getAnnotation(cls, annotationClass));

        }
        return methods;
    }
}
